package zzps.exeed.kernel.aop.asm;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import zzps.exeed.kernel.holder.MethodHolder;
import zzps.exeed.kernel.holder.PandaHolder;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class TargetClassVisitor extends ClassVisitor {
    private PandaHolder<?> pandaHolder;
    private Set<MethodDefinition> constructors = new HashSet<>();
    private Set<MethodDefinition> methods = new HashSet<>();
    private boolean finaled;
    protected TargetClassVisitor(PandaHolder<?> pandaHolder) {
        super(Opcodes.ASM9);
        this.pandaHolder = pandaHolder;
    }


    public boolean isFinaled() {
        return finaled;
    }

    public Set<MethodDefinition> getConstructors() {
        return constructors;
    }

    public List<MethodDefinition> getMethods() {
        return methods.stream().toList();
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        if (access == Opcodes.ACC_FINAL){
            finaled = true;
        }else {
            if (superName != null){
                processSuper(superName);
            }
        }
    }

    //其实只需要将需要代理的方法拿到就行
    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        if (finaled){
            return super.visitMethod(access, name, descriptor, signature, exceptions);
        }
        if ("<init>".equals(name)){
            MethodDefinition constructor = new MethodDefinition(access, name, descriptor);
            constructors.add(constructor);
        }else if (!"<clinit>".equals(name)){
            if (access == Opcodes.ACC_FINAL || access == Opcodes.ACC_STATIC || access == Opcodes.ACC_ABSTRACT){
                //final static abstract
                return super.visitMethod(access, name, descriptor, signature, exceptions);
            }
            if (access == Opcodes.ACC_PUBLIC){
                //public
                Map<Method, MethodHolder> methodedHolderMap = pandaHolder.methodHolderMap();
                for (Method method : methodedHolderMap.keySet()) {
                    if (method.getName().equals(name)){
                        //只对切点的方法进行重写实现
                        MethodDefinition methodDefinition = new MethodDefinition(access, name, descriptor);
                        if (!methods.contains(methodDefinition)){
                            methods.add(methodDefinition);
                        }
                    }
                }
            }
        }
        return super.visitMethod(access, name, descriptor, signature, exceptions);
    }

    private void processSuper(String superName) {
        if(superName.equals("java/lang/Object")){
            return ;
        }
        ClassReader reader = null;
        try {
            reader = new ClassReader(superName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        TargetClassVisitor visitor = new TargetClassVisitor(pandaHolder);
        reader.accept(visitor, ClassReader.SKIP_DEBUG);
        for (MethodDefinition methodDefinition : visitor.methods) {
            if (!methods.contains(methodDefinition)){
                methods.add(methodDefinition);
            }
        }
    }
}
